// fn = comppse(f1. f2, f3)
// b = fn(a)
// 如果一个函数要经过多个函数处理才能得到最终值，这个时候可以把中间过程的函数合并成一个函数
// 函数就像是数据的管道，函数组合就是把这些管道连接器来，让数据穿过多个管道形成最终的结果
// 函数组合默认从右到左执行

// 组合函数
// function compose(f, g) {
//     return function(x) {
//         return f(g(x))
//     }
// }
// function first (arr) {
//     return arr[0]
// }
// function reverse(arr) {
//     return arr.reverse()
// }
// 从右到左运行
// let last = compose(first, reverse)
// console.log(last([1,2,3,4]))


// lodash中的函数组合
// lodash中的组合函数flow()或者flowRight()，他们都可以组合多个函数
// flow()是左到右运行。flowRight()是右到左，这个使用的更加多一些
const { split } = require('lodash')
const _ = require('lodash')
// const toUpper = s => s.toUpperCase()
// const reverse = arr => arr.reverse()
// const first = arr => arr[0]

// // const f = _.flowRight(toUpper,first,reverse)
// // const f = _.flowRight(_.flowRight(toUpper,first), reverse)
// const f = _.flowRight(toUpper,_.flowRight(first, reverse))

// console.log(f(['one', 'two', 'three']))


// 模拟实现lodash的flowRight方法
// 多函数组合
// TODO 实现ES6中的reduce方法的源码
// ES6中的reduce方法参考： https://blog.csdn.net/weixin_41229588/article/details/106858685
// function compose (...fns) {
//     return function(value) {
//         return fns.reverse().reduce(function(acc, fn, index, arr) {
//             return fn(acc)
//         }, value)
//     }
// }
// ES6写法
// const compose = (...fns) => value => fns.reverse.reduce((acc, fn)=> fn(acc), value)

// const toUpper = s => s.toUpperCase()
// const reverse = arr => arr.reverse()
// const first = arr => arr[0]
// const f = compose(toUpper,first,reverse)
// console.log(f(['one', 'two', 'three']))


// 函数的组合要满足结合律
// let f = compose(f, g, h)
// let associative = compose( compose(f, g), h) === compose(f, compose(g, h))
// true

// 调试组合函数
// const trace = _.curry((tag, v) => {
//     console.log(tag, v)
//     return v
// })

// TODO 为什参数的位置要互换
// const split = _.curry((sep, str) => _.split(str, sep))
// const join = _.curry((sep, array) => _.join(array, sep))
// const map = _.curry((fn, array) => _.map(array, fn))

// const f = _.flowRight(join('-'), trace('map 之后'), map(_.toLower), trace('split 之后'), split(' '))
// constf=fp.flowRight(fp.join('-'), fp.map(_.toLower), fp.split(' '))
// console.log(f('NEVER SAY DIE'))

// lodash/fp // TODO 
// lodash的fp模块提供了实用的对函数式编程友好的方法
// 提供了不可变auto-curried iteratee-first data-last的方法

// lodash 模块
// console.log(_.map(['a', 'b', 'c'], _.toUpper));
// console.log(_.map(['a', 'b', 'c']));
// console.log(_.split('Hello World', ' '));
// lodash/fp 模块
const fp = require('lodash/fp')
// fp.map(fp.toUpper, ['a', 'b', 'c'])
// fp.map(fp.toUpper)(['a', 'b', 'c'])
// fp.split(' ', 'Hello World')
// fp.split(' ')('Hello World')

// Point Free
// 我们可以把数据处理的过程定义成与数据无关的合成运算，不需要用到代表数据的那个参数，只要把简单的运算步骤合到一起，在使用这种模式之前我们需要定义一些辅助的基本运算函数。
constfirstLetterToUpper=fp.flowRight(join('. '),fp.map(fp.flowRight(fp.first, fp.toUpper)), split(' '))
console.log(firstLetterToUpper('world wild web'))